package cn.hamster3.inventory.tweaks;

import cn.hamster3.inventory.tweaks.config.ItemSorter;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.java.JavaPlugin;

import java.util.*;

public final class InventoryTweaks extends JavaPlugin implements Listener {
    private HashMap<UUID, Long> lastClickTime;
    private HashSet<UUID> notifiedPlayer;
    private List<String> messages;

    @Override
    public void onEnable() {
        saveDefaultConfig();
        reloadConfig();
        messages = getConfig().getStringList("messages");
        lastClickTime = new HashMap<>();
        notifiedPlayer = new HashSet<>();
        Bukkit.getPluginManager().registerEvents(this, this);
    }

    @EventHandler(ignoreCancelled = true)
    public void onInventoryClick(InventoryClickEvent event) {
        if (event.getClickedInventory() != null) {
            // 如果玩家点击的不是GUI外面的空白处则不处理
            return;
        }
        if (!event.isLeftClick()) {
            // 如果不是左键点击则不处理
            return;
        }

        HumanEntity player = event.getWhoClicked();
        UUID uuid = player.getUniqueId(); //玩家的UUID

        //双击判定，计算两次点击的毫秒差
        long now = System.currentTimeMillis();
        long lastTime = lastClickTime.getOrDefault(uuid, 0L);
        lastClickTime.put(uuid, now);
        if (now >= lastTime + 500) {
            // 要求在500毫秒内点击两次GUI空白处才会进行背包整理
            return;
        }

        Inventory topInventory = event.getView().getTopInventory(); // 界面上半部分GUI
        Inventory bottomInventory = event.getView().getBottomInventory();  // 界面下半部分GUI

        int startIndex; // 整理的背包槽位范围
        int endIndex; // 整理的背包槽位范围
        Inventory sortInventory; // 需要整理的背包

        // 检查背包类型，并分配需要整理的背包
        switch (topInventory.getType()) {
            case BARREL:
            case CHEST:
            case ENDER_CHEST:
            case SHULKER_BOX: {
                startIndex = 0;
                endIndex = topInventory.getSize();
                sortInventory = topInventory;
                break;
            }
            case CRAFTING: {
                // 如果 topInventory 的 type 是 CRAFTING ，那么说明这个gui是玩家的背包
                startIndex = 9;
                endIndex = 36;
                sortInventory = bottomInventory;
                break;
            }
            default:
                // 其他type一律不处理
                return;
        }

        ArrayList<ItemStack> sortStacks = new ArrayList<>();

        for (int i = startIndex; i < endIndex; i++) {
            ItemStack stack = sortInventory.getItem(i);
            if (stack == null || stack.getType() == Material.AIR) {
                // null和空气直接添加，不判断重复物品
                sortStacks.add(stack);
                continue;
            }

            if (mergeAddItem(sortStacks, stack, sortInventory.getMaxStackSize())) {
                sortStacks.add(stack);
            }
        }

        sortStacks.sort(ItemSorter.instance);

        // 把排好序之后的物品set进Inventory里
        for (int i = 0; i < endIndex - startIndex; i++) {
            ItemStack stack = null;
            if (i < sortStacks.size()) {
                stack = sortStacks.get(i);
            }
            sortInventory.setItem(i + startIndex, stack);
        }

        if (player instanceof Player) {
            if (notifiedPlayer.add(uuid)) {
                // 第一次整理成功时给出提示
                for (String s : messages) {
                    player.sendMessage(s);
                }
            }
            Bukkit.getScheduler().runTaskLater(this, ((Player) player)::updateInventory, 1);
        }
    }

    /**
     * 添加一个物品到集合中的相同项
     * 这个方法只会给集合中已有的物品设置更多的物品数量
     * 而不会把addItem添加到stacks中
     *
     * @param stacks                要添加物品的集合
     * @param addItem               要添加的物品
     * @param inventoryMaxStackSize 集合中物品允许的最大堆叠
     * @return 添加完后物品是否还有剩余
     */
    private boolean mergeAddItem(Collection<ItemStack> stacks, ItemStack addItem, int inventoryMaxStackSize) {
        for (ItemStack sameItem : stacks) {
            if (sameItem == null || sameItem.getType() == Material.AIR) {
                // null和空气直接添加，不判断重复物品
                continue;
            }
            int sameItemAmount = sameItem.getAmount();
            // 背包或物品类型允许的最大堆叠
            int maxStackSize = Math.min(sameItem.getType().getMaxStackSize(), inventoryMaxStackSize);
            if (sameItemAmount >= maxStackSize) {
                // 如果该物品已达到最大堆叠则无视它
                continue;
            }
            if (!sameItem.isSimilar(addItem)) {
                // 如果该物品和sortInventoryItem不匹配则无视它
                continue;
            }
            int setAmount = maxStackSize - sameItemAmount; //还差多少物品填满
            int sortInventoryItemAmount = addItem.getAmount();

            if (sortInventoryItemAmount < setAmount) {
                sameItem.setAmount(sameItemAmount + sortInventoryItemAmount);
                return false;
            } else {
                sameItem.setAmount(maxStackSize);
                addItem.setAmount(sortInventoryItemAmount - setAmount);
            }
        }
        return true;
    }
}
